import pyglet
import pyglet.gl as gl
from struct import *
from xml.dom.minidom import parse
import xml
import os,copy,sys
import string,random

import actuator

class CharInfo(object):
    uc=0x982d
    kuntomi=("Kun","Kun2")
    onyomi=("Onyomi")
    imi=("head","counter for large animals")



class GameState(object):
    name="VOID"
    
    def __init__(self,iName,iTitle,iWindow):
        self.name=iName
        self.title=iTitle
        self.window=iWindow
        
        self.keys=iWindow.keys
        
        # Load the font and record the screen dimensions
        
        
        
        
    def activate(self):
        self.window.push_handlers(self)
        
    def deActivate(self):
        self.window.remove_handlers(self)
        
    def step(self,dt):
        pass
    
    def draw(self,dt):
        pass
        
    def on_mouse_press(self, x, y, button, modifiers):
        return False
    
    def on_mouse_release(self, x, y, button, modifiers):
        return False
    
    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        return False
    
    def on_key_press(self, symbol, modifiers):
        return False


class Button(object):
    HIDDEN=0
    ACTIVE=1
    INACTIVE=2
    PRESSED=3
    
    def __init__(self,iParent,iPos,iImgName,iCallBack):
        self.position=iPos
        self.parent=iParent
        
        self.callback=iCallBack
        self.oldStatus=self.INACTIVE
        self.status=Button.ACTIVE
        self. isPressed=False
        
        #self.callback=copy.copy(iCallback)
        
        self.images=[None,]
        self.images.append(pyglet.resource.image(iImgName+"_on.png"))
        self.images.append(pyglet.resource.image(iImgName+"_off.png"))
        self.images.append(pyglet.resource.image(iImgName+"_pressed.png"))
        self.size=(self.images[1].width,self.images[1].height)
        
        for img in self.images:
            if img:
                img.anchor_x = img.width // 2
                img.anchor_y = img.height // 2
            
##        backColors=[
##            (255,255,255, 255),
##            (128, 255, 0, 255),
##            (128, 0, 255, 255)
##            ]
##            
##        for i in range(len(self.backColors)):
##            c=backColors[i]
##            
##            img=pyglet.image.SolidColorImagePattern(c).create_image(*iSize)
##            
##                  
##            self.images.append(img)

    
        
    def isPosIn(self,pos):
        
        xa,ya=pos
        x,y=self.position
        w,h=self.size
        
        if abs(x-xa)<w//2 and abs(y-ya)<h//2 :
            return True
        return False
    
    def on_mouse_press(self, x, y, button, modifiers):
        
        if self.isPosIn((x,y)):
            self.oldStatus=self.status
            if self.oldStatus==Button.INACTIVE:
                self.status=Button.ACTIVE
            else :
                self.status=Button.INACTIVE

            self.isPressed=True
            return True
        return False
    
    def on_mouse_release(self,x,y,button,modifiers):
        self.isPressed=False

    
    def draw(self):
        if self.status==Button.HIDDEN:
            return

        if self.isPressed:
            self.images[Button.PRESSED].blit(*self.position)
        else :      
            self.images[self.status].blit(*self.position)
        
                    

    

class Card(object):
    HIDDEN=0
    ACTIVE=1
    INACTIVE=2
    PRESSED=3
    KANJI=1
   
    
    def __init__(self,iParent,iCharInfo,iPos,iSize,iFont):
        self.position=iPos
        self.parent=iParent
        self.charInfo=iCharInfo
        self.size=iSize
        self.status=self.KANJI
        self.selected=False
        s=self.charInfo.uc
                
        x,y=self.position
        
        w,h=iSize
        x1=int(x+w/2)
        y1=int(y+h/2*1.3)
        self.center=(x1,y1)
        fsize=w*0.8
        self.label=pyglet.text.Label(s,
                    x=x1,
                    y=y1,
                    width=fsize,
                    height=fsize,
                    anchor_x="center",
                    anchor_y="center",
                    color=(0,0,0,190),
                    font_size=fsize,
                    font_name=self.parent.fontName)
                    
                    
        self.images=[]
        
        self.backColors=[
            (255, 128, 0, 255),
            (128, 255, 0, 255),
            (128, 0, 255, 255),
            (255, 128, 0, 12)]
            
        for i in range(len(self.backColors)):
            c=self.backColors[i]
            
            img=pyglet.image.SolidColorImagePattern(c).create_image(*iSize)
            
                  
            self.images.append(img)

        
            
    def isPosIn(self,pos):
        if self.status==Card.INACTIVE:
            return False
        
        
        xa,ya=pos
        x,y=self.center
        w,h=self.size
        
        if abs(x-xa)<w//2 and abs(y-ya)<h//2 :
            return True
        return False
    
    
    
    def draw(self):
        if self.status==Card.INACTIVE:
            return

         
        if self.selected:
            if self.status==self.KANJI:
                
                self.images[Card.KANJI].blit(*self.position)

                self.label.draw()
        else :
            self.images[Card.HIDDEN].blit(*self.position)
        
##            
                
            
                
        
        
##    def drawText(self,txt,y,dy):
##        ss=txt.split(",")
##        
##        for s in ss:
##            text = self.parent.font2.render(s, 1, (10, 10, 10))
##            textpos = text.get_rect()
##            textpos.centerx = self.surface.get_rect().centerx
##            textpos.centery = y
##            self.surface.blit(text, textpos)
##            y+=dy
##        y+=dy//2
##        return 

class KanjiInfoPanel(GameState):
    def __init__(self,iName,iKanji,iWindow,iCompounds,iFontName):
        super(KanjiInfoPanel,self).__init__(iName,"Kanji Info Panel",iWindow)
        self.fontName=iFontName
        self.compounds=iCompounds
        
        self.charInfo=iKanji
        ss=[]
        ss.append("<p align=\"center\"><font face=\"%s\" size=\"7\" color=maroon><b>%s</b></font><br /><br />"%(self.fontName,self.charInfo.uc))
        ss.append("<font face=\"%s\" size=\"5\" color=red><b>"%(self.fontName))
        for s in self.charInfo.onyomi:
            ss.append("%s<br />"%(s))

        ss.append("<b /></font>")

        ss.append("<br />")
        ss.append("<font face=\"%s\" size=\"5\" color=green>"%(self.fontName))

        for s in self.charInfo.kunyomi:
            ss.append("%s<br />"%(s))
        ss.append("<br />")
        ss.append("<b /></font>")


        ss.append("<font face=\"Arial\" size=\"4\" color=white>")

        for s in self.charInfo.imi:
            ss.append("%s<br />"%(s))

        ss.append("</font></p>")
        ss.append("<p align='center'><font face='%s' size=\"6\" color=white>"%(self.fontName))

        if self.compounds.has_key(self.charInfo.uc):
            related=self.compounds[self.charInfo.uc]
            for word in related:
                ss.append("<br />%s</font><font face='%s' size=\"4\" color=white> - %s - %s<br />"%(word[0],self.fontName,word[2],word[1]))
                
        ss.append("</font></p>")
        s=string.join(ss)
        self.center=(iWindow.width//2,iWindow.height//2)
        self.label = pyglet.text.HTMLLabel(s,
            x=0, y=0,width=self.window.width*0.8,
            anchor_x='center', anchor_y='center', multiline=True)
    
    def draw(self,dt):
        gl.glPushMatrix()
        gl.glTranslatef(self.center[0],self.center[1],0.)
        gl.glScalef(1.4,1.4,1.)

        self.label.draw()
        gl.glPopMatrix()
    def on_key_press(self, symbol, modifiers):
        self.window.popGS()

    def on_mouse_press(self, x,y, button, modifiers):
        self.window.popGS()

class Menu(GameState):
       
    def __init__(self,iName,iTitle,iWindow,iFontName):
        super(Menu,self).__init__(iName,iTitle,iWindow)
        self.fontName=iFontName
        self.items = []
        self.title_text = pyglet.text.Label(iTitle, 
                                            font_name=self.fontName,
                                            font_size=36,
                                            x=self.window.width // 2, 
                                            y=460,
                                            anchor_x='center',
                                            anchor_y='center',
                                            color=[255,255,255,255])

    def reset(self):
        self.selected_index = 0
        self.items[self.selected_index].selected = True

    def on_key_press(self, symbol, modifiers):
        if symbol == pyglet.window.key.DOWN:
            self.selected_index += 1
        elif symbol == pyglet.window.key.UP:
            self.selected_index -= 1
        else:
            self.items[self.selected_index].on_key_press(symbol, modifiers)
        self.selected_index = min(max(self.selected_index, 0), 
                                  len(self.items) - 1)

##        if symbol in (pyglet.window.key.DOWN, pyglet.window.key.UP) and self.window.enable_sound:
##            bullet_sound.play()

    def draw(self,dt):
        gl.glPushAttrib(gl.GL_CURRENT_BIT)
        gl.glColor3f(1.0,1.0,1.0)
        self.title_text.draw()
        for i, item in enumerate(self.items):
            item.draw(i == self.selected_index)
        gl.glPopAttrib()
        
    
class MainMenu(Menu):
    def __init__(self,iName,iTitle,iWindow,iFontName):
        super(MainMenu, self).__init__(iName,iTitle,iWindow,iFontName)
        
        self.cursorImage=pyglet.resource.image('blue_light.png')
        self.cursorImage.anchor_x = self.cursorImage.width // 2
        self.cursorImage.anchor_y = self.cursorImage.height // 2
        self.cursorImage_flip = pyglet.resource.image('blue_light.png', flip_x=True)
        dy=40
        y=340
        self.items.append(MenuItem(self,'New Game',y, self.begin_game))
        y-=dy
        self.items.append(MenuItem(self,'Quit', y, sys.exit))
        
        self.reset()

    def begin_game(self):
        G=KanjiGameState("Game","Kanji Game",self.window)
        
        self.window.switchGameState(G)
        

    
        

class MenuItem(object):
    pointer_color = (.46, 0, 1.)
    inverted_pointers = False

    def __init__(self, iWindow,label, y, activate_func):
        self.y = y
        self.window=iWindow
        self.pointer_image=iWindow.cursorImage
        self.pointer_image_flip=iWindow.cursorImage_flip
        self.text = pyglet.text.Label(label,
                                      font_name=self.window.fontName,
                                      font_size=14,
                                      x=iWindow.window.width // 2, 
                                      y=y,
                                      anchor_x='center',
                                      anchor_y='center',
                                      color=[255,180,0,255])
        self.activate_func = activate_func
        print iWindow.window.width // 2
    def draw_pointer(self, x, y, color, flip=False):
       
        # Tint the pointer image to a color
        gl.glPushAttrib(gl.GL_CURRENT_BIT)
        gl.glColor3f(*color)
        if flip:
            self.pointer_image_flip.blit(x, y)
        else:
            self.pointer_image.blit(x, y)
        gl.glPopAttrib()

    def draw(self, selected):
        
        
        self.text.draw()

        if selected:
            
            self.draw_pointer(
                self.text.x - self.text.content_width / 2 - 
                    self.pointer_image.width / 2,
                self.y, 
                self.pointer_color,
                self.inverted_pointers)
            self.draw_pointer(
                self.text.x + self.text.content_width / 2 + 
                    self.pointer_image.width / 2,
                self.y,
                self.pointer_color,
                not self.inverted_pointers)

    def on_key_press(self, symbol, modifiers):
        if symbol == pyglet.window.key.ENTER and self.activate_func:
            self.activate_func()
            

class ToggleMenuItem(MenuItem):
    pointer_color = (.27, .82, .25)
    inverted_pointers = True

    def __init__(self, iWindow,label, value, y, toggle_func):
        
        self.value = value
        self.label = label
        self.toggle_func = toggle_func
        super(ToggleMenuItem, self).__init__(iWindow,self.get_label(), y, None)

    def get_label(self):
        return self.label + (self.value and ': ON' or ': OFF')

    def on_key_press(self, symbol, modifiers):
        if symbol == key.LEFT or symbol == key.RIGHT:
            self.value = not self.value
            self.text.text = self.get_label()
            self.toggle_func(self.value)
            if self.window.options["enable_sound"]:
                bullet_sound.play()


class SubWindow(object):
    def __init__(self,iGS,iPos,iSize):
        self.position=iPos
        self.size=iSize
        self.gameState=iGS
        self.screenCenter=[iSize[0]//2,iSize[1]//2]

    def isScreenPointIn(self,iPos):
        x,y=iPos
        w,h=self.size
        x-=self.position[0]
        y-=self.position[1]
        
        if 0<=x<w and 0<=y<h :
            return (x,y)
        return None
    
    def getRelativeScreenCoord(self,iPt):
        relPos=self.isScreenPointIn(iPt)
        if not relPos:
            print "error, point outside window"
            return None
        
        x,y=relPos
        w,h=self.size
        u = float(x) / float(w)
        v = float(y) / float(h)
        return (u,v)

    def prepareView(self):
        """
        Updates the view offset based on the center of the screen.

        Recalculates the necessary projection.
        """
        gl.glViewport(self.position[0],self.position[1], self.size[0],self.size[1])
        
        gl.glMatrixMode(gl.GL_PROJECTION)
        gl.glLoadIdentity()

        
        gl.gluOrtho2D(  0,self.size[0],0,self.size[1])
        
        gl.glMatrixMode(gl.GL_MODELVIEW)
        gl.glLoadIdentity()
    
    def on_mouse_press(self, x, y, button, modifiers):
        rc=self.isScreenPointIn((x,y))
        
        if not rc:
            print "Outside bounds"
            return False
        return False
    
    def on_mouse_release(self, x, y, button, modifiers):
        rc=self.isScreenPointIn((x,y))
        if not rc:
            return False
        return False
    
    def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
        rc=self.isScreenPointIn((x,y))
        if not rc:
            return False
        return False
    
    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        rc=self.isScreenPointIn((x,y))
        if not rc:
            return False
        return False

class Player(object):
    name="Toto"
    score=0
    
class KanjiWindow(SubWindow):
    def __init__(self,iGS,iPos,iSize):
        super(KanjiWindow,self).__init__(iGS,iPos,iSize)
        self.selected=None
        self.nSelected=0
        self.actuator=None
        
        self.players=iGS.players
        self.currentPlayer=iGS.currentPlayer
        
        self.widgets=[]
        self.widgets.append(Button(self,(900,100),"button_p",None))
        for w in self.widgets:
            self.gameState.window.push_handlers(w)
    
        self.scoreLabel = pyglet.text.HTMLLabel("Test", \
            x=iGS.window.width-150, y=iGS.window.height-100,width=150,
            anchor_x='center', anchor_y='top', multiline=True)
    
        self.refreshScores()
        
    def refreshScores(self):
        ss=[]
        ss.append("<font face=\"Arial\" size=\"6\" color=green><b><i>Scores</i></b></font><br /><br />")
        for p in self.players:
            if self.currentPlayer==p:
                color="white"
            else : 
                color="green"
                
            ss.append("<font face=\"Arial\" size=\"4\" color=%s><b>%s</b>..."%(color,p.name))
            ss.append("(%d)</font><br />"%(p.score))
        
        
        s=string.join(ss)
        self.scoreLabel.text=s
        
    def on_mouse_press(self, x, y, button, modifiers):
        mp=self.isScreenPointIn((x,y))
        if not mp:
            return False

        pointed=None
       
        if button & (pyglet.window.mouse.LEFT ):
            #print event.button
            
            for c in self.gameState.cards:
                if c.isPosIn(mp):
                    
                    pointed=c
                    break
            if pointed and pointed.status!=Card.INACTIVE:
                if self.nSelected>0:
                    if self.nSelected==1:
                        if not pointed==self.selected:
                            pointed.selected=True
                            self.nSelected+=1
                            if self.selected.charInfo.uc==pointed.charInfo.uc:
                                
                                #Found pair
                                pointed.status=Card.INACTIVE
                                self.selected.status=Card.INACTIVE
                                self.selected.selected=False
                                self.selected=None
                                self.nSelected=0 
                                self.currentPlayer.score+=2
                            else:
                                self.currentPlayer.score-=1
                                self.currentPlayer=self.gameState.nextPlayer()
                            self.refreshScores()    
                        else:
                            #clicked twice the same card
                            pointed.selected=False
                            self.nSelected=0
                            
                            self.selected=None
                    else :
                        for cd in self.gameState.cards:
                            cd.selected=False
                            
                        self.selected=None
                        self.nSelected=0    
                else :
                    self.selected=pointed
                    self.nSelected=1
                    pointed.selected=True
                return True

        if button & (pyglet.window.mouse.RIGHT ):
            
            for c in self.gameState.cards:
                if c.isPosIn(mp):
                    pointed=c
                    ci=pointed.charInfo
                    self.gameState.window.switchGameState(KanjiInfoPanel("Kanji Info",ci,self.gameState.window,self.gameState.compounds,"MS Mincho"))
                    return True
                
        return False

    
    def step(self,dt):
        if self.actuator:
            self.finished,dx=self.actuator.val()
            #self.label.x=self.pos[0]
            print self.screenCenter[0]
            self.screenCenter[0]=self.screenCenter[0]+dx*0.3
            
            if self.finished:
                #can do this because weakly bound to parent
                self.actuator=None
        
            
    def draw(self):
        
        self.scoreLabel.draw()
        for w in self.widgets:
            w.draw()
            
    def on_key_press(self, key, modifiers):
        if key == pyglet.window.key.LEFT:
            if not self.actuator:
                self.actuator=actuator.SqrActuator(0.,30.,1.)
            return True
        if key == pyglet.window.key.RIGHT:
            if not self.actuator:
                self.actuator=actuator.SqrActuator(0.,-30.,1.)
            return True
        
        return False
        

class KanjiGameState(GameState):
    def __init__(self,iName,iTitle,iWindow):
        super(KanjiGameState,self).__init__(iName,iTitle,iWindow)
        self.fontName=iWindow.font_name
        self.cardSize=(180,180)
        self.font = pyglet.font.load(self.fontName,self.cardSize[0]*0.9)
        self.players=[]
        
        for pn in ["Mirabelle","Xavier","Serge"]:
            P=Player()
            P.name=pn
            self.players.append(P)
        self.currentPlayer=self.players[0]
        
        self.resetScores()

        self.load()
        self.mainWindow=KanjiWindow(self,(0,0),self.window.screenSize)
        iWindow.push_handlers(self.mainWindow)
        
        
        
        
    def resetScores(self):
        for p in self.players:
            p.score=0
    
    def nextPlayer(self):
        nextP=self.players[0]
        takeNext=False
        for p in self.players:
            if takeNext:
                nextP=p
                break
            elif p==self.currentPlayer:
                takeNext=True
        self.currentPlayer=nextP
        return nextP
        
    def on_show(self):
        """
        Callback: the window was shown.
        """
        pass
    
    def draw(self,dt):
        self.mainWindow.prepareView()

        for c in self.cards:
            c.draw()
            
        self.mainWindow.draw()

    def step(self,dt):
        self.mainWindow.step(dt)

    
    def load(self):

        fullname = os.path.join('res', "kanji.xml")
        
        self.kanjiDB={}
        datasource=open(fullname)
        
        dom2 = parse(datasource)   # parse an open file

        nodes=dom2.getElementsByTagName("KANJI")
        
        for n in nodes:
            K={}
            uc=int(n.getAttribute("code"))
            ns=int(n.getAttribute("strokes"))
            K["code"]=uc
            K["strokes"]=ns
            
            for cn in n.childNodes:
                if cn.nodeType!=xml.dom.Node.TEXT_NODE:
                    tag=string.lower(cn.tagName)
                    if cn.firstChild:
                        K[tag]=cn.firstChild.nodeValue
                    
            self.kanjiDB[uc]=K    
            
        dom2.unlink()
        
        fullname = os.path.join('res', "mydata.xml")
        datasource=open(fullname)
        
        dom2 = parse(datasource)   # parse an open file

        nodes=dom2.getElementsByTagName("Compound")
        
        self.compounds={}
        for cmp in nodes:
            s=cmp.getAttribute("value")
            imi=cmp.getAttribute("imi")
            yomi=cmp.getAttribute("yomi")
            l=(s,imi,yomi)
            for ch in s:
                if not self.compounds.has_key(ch):
                    self.compounds[ch]=[]
    
                self.compounds[ch].append(l)
                    
               
        nodes=dom2.getElementsByTagName("Lesson")

        self.cards=[]

        dx,dy=self.cardSize

                    
        kk=[]

        for lesson in nodes:
            if lesson.getAttribute("id")=="1":
                s=lesson.firstChild.nodeValue
                for ch in s:
                    uc=ord(ch)
                    
                    if self.kanjiDB.has_key(uc):
                        k=self.kanjiDB[uc]
                        K=CharInfo()
                        K.uc=ch
                        
                        K.onyomi=string.split(k.get("on",""),"/")
                        K.kunyomi=string.split(k.get("kun",""),"/")
                        K.imi=string.split(k.get("imi",""),"/")
                        
                        kk.append(K)
            
                        kk.append(copy.deepcopy(K))
            
                        
                    
##        for n in nodes:
##            K=CharInfo()
##            s="\u"+n.getAttribute("code")
##            
##            uc=ord(n.getAttribute("code"),16)
##            
##            K.uc=unichr(ch)
##            K.onyomi=n.getAttribute("onyomi")
##            K.kunyomi=n.getAttribute("kunyomi")
##            K.imi=n.getAttribute("imi")
##            
##            kk.append(K)
##            
##            kk.append(copy.deepcopy(K))
        
        random.shuffle(kk)
        
        nx=4
        ny=4

        nc=0
        
        for k in kk:
            x=nc//4
            y=nc%4
            
            self.cards.append(Card(self,k,(int(x*dx+20),int(y*dy+20)),((int(dx*0.9),int(dy*0.9))),self.font))

            nc+=1
            
            
            #print n.getAttribute("onyomi")
            
        dom2.unlink()
        nc=0
        
        for c in self.cards:
            x=nc//4
            y=nc%4
            nc+=1
            c.position=[(x)*dx+20,(y)*dy+20]
            


class Main(pyglet.window.Window):
    
    name="Kanji Memory"
    font = None
    font_name="MS Mincho"
    
    keys=pyglet.window.key.KeyStateHandler()
        
            
    def __init__(self):
        # Initialise screen
        
        config=gl.Config(stencil_size=8)
    
        super(Main, self).__init__(config=config,height=800,width=1024, resizable=False)
        
        gl.glEnable(gl.GL_BLEND)
        self.screenSize =(self.width, self.height)
        
        pyglet.resource.path=['','res']
        pyglet.resource.reindex()
        pyglet.resource.add_font('msmincho.ttc')
        self.gsStack=[]

        self.fontName="MS Mincho"
        self.currentGameState=MainMenu("KanjiGame","KanjiGame",self,self.fontName)
        #self.currentGameState=KanjiGameState("KanjiGame","KanjiGame",self)
        self.currentGameState.activate()
        
        
        self.hz=20.
        
        # Fill background
        
        
    
    def run(self):
        """
        Main loop.
        """
        
        
        pyglet.clock.schedule_interval(self.SimulationLoop, 1.0 / self.hz)
        pyglet.clock.set_fps_limit(1.0 / self.hz)
        
        pyglet.app.run()

    def SimulationLoop(self, dt):
        """
        The main simulation loop. Don't override this, override Step instead.
        And be sure to call super(classname, self).Step(settings) at the end
        of your Step function.
        """

        
        # Clear the screen
        self.clear()
        
        # Update the keyboard status
        self.push_handlers(self.keys)

        # Reset the text position
        #self.SetTextLine(30)
        gs=self.currentGameState
        gs.step(dt)
        gs.draw(dt)
        
        
        self.invalid = True
        
        
    def switchGameState(self,iGS):
        self.gsStack.append(self.currentGameState)
        self.currentGameState.deActivate()
        self.currentGameState=iGS
        self.currentGameState.activate()
        
        
    def popGS(self):
        self.currentGameState.deActivate()
        if len(self.gsStack)>0:
            self.currentGameState=self.gsStack.pop()
            self.currentGameState.activate()
        else :
            sys.exit()

        



if __name__ == '__main__': 
    m=Main()
    m.run()
    